﻿using System;
using System.ComponentModel;
using System.Net;
using System.Reflection;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
using System.ServiceModel.Web;
using UFIDA.U9.WSS.ProxyService.Interfaces.Interfaces;
using UFIDA.U9.WSS.ProxyService.Json;
using UFIDA.U9.WSS.ProxyService.Models;
using UFIDA.U9.WSS.ProxyService.Utils;
using UFSoft.UBF.Util.Context;
using UFSoft.UBF.Util.Log;

namespace UFIDA.U9.WSS.DBLog.Behavior.Endpoint
{
    public class DBLogEndpointBehavior : IDispatchMessageInspector, IEndpointBehavior
    {
        private const string HeaderLogIDName = "LogID";
        private static readonly ILogger Logger = LoggerManager.GetLogger(typeof(DBLogEndpointBehavior));

        public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
        {
            if (WebOperationContext.Current == null)
            {
                throw new WebFaultException(HttpStatusCode.BadRequest);
            }

            WSLog wsLog = new WSLog();
            try
            {
                string actionName =
                    OperationContext.Current.IncomingMessageProperties["HttpOperationName"] as string;
                if (string.IsNullOrEmpty(actionName)) return null;
                Type hostType = OperationContext.Current.Host.Description.ServiceType;
                if (hostType == null) return null;
                MethodInfo method = hostType.GetMethod(actionName);
                if (method == null) return null;
                DescriptionAttribute descriptionAttribute =
                    method.GetCustomAttribute(typeof(DescriptionAttribute)) as
                        DescriptionAttribute;
                //日志属性
                string requestContent = MessageHelper.GetContent(ref request);
                //获取代理类的信息
                ContextData contextData = null;
                if (!string.IsNullOrEmpty(requestContent))
                {
                    //特殊处理通用代理服务
                    if (hostType == typeof(ProxyService.Services.ProxyService))
                    {
                        wsLog.IsProxy = true;
                        //获取代理类的信息
                        ProxyData proxyData = JsonHelper.FromJson<ProxyData>(requestContent);
                        if (proxyData != null)
                        {
                            wsLog.ProxyType = proxyData.Proxy;
                            contextData = proxyData;
                        }
                    }
                    else
                    {
                        contextData = JsonHelper.FromJson<ContextData>(requestContent);
                    }
                }

                //替换掉密码
                if (contextData?.Context != null && !string.IsNullOrEmpty(contextData.Context.Password))
                {
                    requestContent =
                        requestContent.Replace("\"" + contextData.Context.Password + "\"", "\"\"");
                    requestContent =
                        requestContent.Replace("'" + contextData.Context.Password + "'", "''");
                }

                string logID = WebOperationContext.Current.IncomingRequest.Headers[HeaderLogIDName];
                if (!string.IsNullOrWhiteSpace(logID))
                    wsLog.LogID = long.Parse(logID);
                Uri requestUri = request.Headers.To;
                wsLog.RequestUrl = requestUri.AbsoluteUri;
                wsLog.EnterpriseID = PlatformContext.Current.EnterpriseID;
                wsLog.ClassName = hostType.FullName;
                wsLog.MethodName = actionName;
                wsLog.MethodDescription = descriptionAttribute != null ? descriptionAttribute.Description : actionName;
                wsLog.StartTime = DateTime.Now;
                wsLog.RequestContent = requestContent;
                wsLog.CallResult = CallResultEnum.Unknown;
                //发送调用前日志
                wsLog.DoBeforeCallLog();
            }
            catch (Exception ex)
            {
                Logger.Error("日志记录异常:{0}", ex.Message);
                Logger.Error(ex);
            }

            return wsLog;
        }

        public void BeforeSendReply(ref Message reply, object correlationState)
        {
            if (correlationState == null) return;
            WSLog wsLog = correlationState as WSLog;
            try
            {
                if (wsLog == null)
                    throw new Exception("BeforeSendReply WSLog is null exception");
                wsLog.EndTime = DateTime.Now;
                string responseContent = MessageHelper.GetContent(ref reply);
                wsLog.ResponseContent = responseContent;
                if (!string.IsNullOrEmpty(responseContent))
                {
                    SimpleReturnMessage returnMessage = JsonHelper.FromJson<SimpleReturnMessage>(responseContent);
                    if (returnMessage != null)
                    {
                        wsLog.CallResult = returnMessage.IsSuccess ? CallResultEnum.Success : CallResultEnum.Failure;
                        wsLog.ErrorMessage = returnMessage.ErrMsg;
                    }
                }

                //发送调用完日志
                wsLog.DoAfterCallLog();
            }
            catch (Exception ex)
            {
                if (wsLog != null)
                    Logger.Error("日志记录异常,LogID:{0}", wsLog.LogID);
                Logger.Error("日志记录异常:{0}", ex.Message);
                Logger.Error(ex);
            }
        }

        public void Validate(ServiceEndpoint endpoint)
        {
        }

        public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
        {
        }

        public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
        {
            endpointDispatcher.DispatchRuntime.MessageInspectors.Add(this);
        }

        public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
        {
        }

        internal class ProxyData : ContextData
        {
            [DataMember] public string Proxy { get; set; }
        }

        internal class ContextData
        {
            [DataMember] public ContextInfo Context { get; set; }
        }

        /// <summary>
        ///     简化返回信息
        /// </summary>
        internal class SimpleReturnMessage : IReturnMessage
        {
            /// <summary>
            ///     编码
            /// </summary>
            [DataMember]
            public int Code { get; set; }

            /// <summary>
            ///     是否成功
            /// </summary>
            [DataMember]
            public bool IsSuccess { get; set; } = true;

            /// <summary>
            ///     错误信息
            /// </summary>
            [DataMember]
            public string ErrMsg { get; set; } = string.Empty;

            /// <summary>
            ///     堆栈信息
            /// </summary>
            [DataMember]
            public string StackString { get; set; } = string.Empty;
        }
    }
}